package com.zzb.projectfactory.framework.common;

import com.alibaba.fastjson.JSON;
import com.zzb.projectfactory.framework.utils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;

/**
 * 基本的增删改查mapper
 * Created by 瑱彬 on 2016/9/18.
 */
@Component
public abstract class BaseDAO<T extends BaseEntity, REPOSITORY extends BaseRepository<T>> {
    @Autowired
    JdbcTemplate jdbcTemplate;
    /**
     * 注入JpaRepository
     */
    public abstract REPOSITORY getRepository();
    public JdbcTemplate getJdbcTemplate(){
        return jdbcTemplate;
    }

    public T selectById(String id ){
        return getRepository().findOne(id);
    }

    public T trash(T t, String updater) throws DaoException {
        try {
            t.setUpdater(updater);
            t.setActivate(false);
            t.setUpdateTime(new Date());
            return getRepository().save(t);
        } catch (Exception e) {
            throw new DaoException(e);
        }
    }

    public List<T> trash(List<T> list, String updater) throws DaoException {
        try {
            list.forEach(t -> {
                t.setUpdater(updater);
                t.setUpdateTime(new Date());
                t.setActivate(false);
            });
            return getRepository().save(list);
        } catch (Exception e) {
            throw new DaoException(e);
        }
    }

    /**
     * 恢复删除
     */
    public T recovery(T t, String updater) throws DaoException {
        try {
            t.setUpdater(updater);
            t.setActivate(true);
            t.setUpdateTime(new Date());
            return getRepository().save(t);
        } catch (Exception e) {
            throw new DaoException(e);
        }
    }

    public List<T> recovery(List<T> list, String updater) throws DaoException {
        try {
            list.forEach(t -> {
                t.setUpdater(updater);
                t.setUpdateTime(new Date());
                t.setActivate(true);
            });
            return getRepository().save(list);
        } catch (Exception e) {
            throw new DaoException(e);
        }
    }

    /**
     * 物理删除
     */
    public void delete(String id) {
        getRepository().delete(id);
    }

    public void delete(T t) {
        getRepository().delete(t);
    }

    public void delete(List<String> ids) {
        List<T> list = selectByIds(ids);
        deleteRecords(list);
    }

    public void deleteRecords(List<T> list) {
        getRepository().deleteInBatch(list);
    }

    /**
     * 保存或更新
     */
    public T createOrUpdate(T record, String operator) {
        return getRepository().save(mergeCreateOrUpdateObject(record, operator));
    }

    public List<T> createOrUpdate(List<T> records, String operator) {
        records.forEach(record -> record = mergeCreateOrUpdateObject(record, operator));
        return getRepository().save(records);
    }

    /**
     * 合并 createOrUpdate对象
     * 如果record已经持久化，则返回一个更新对象
     * 如果record未持久化，则返回一个创建对象
     */
    private T mergeCreateOrUpdateObject(T record, String operator) {
        T t = null;
        if (record.getId() != null){
            t = selectById(record.getId());
        }
        if (t == null) {
            record.setId(null);
            record.setCreator(operator);
            record.setUpdater(operator);
            if(record.getCreateTime() == null) record.setCreateTime(new Date());
            record.setUpdater(operator);
            record.setUpdateTime(new Date());
            if(record.getActivate() == null) record.setActivate(true);
            return record;
        } else {
            BeanUtils.copyProperties(record,t);
            t.setUpdateTime(new Date());
            t.setUpdater(operator);
            return t;
        }
    }

    /**
     * 插入，如果存在相同id抛异常
     */
    public T create(T record, String creator) throws DaoException {
        if (record.getId() != null && getRepository().exists(record.getId())) {
            throw new DaoException("创建失败，【" + JSON.toJSONString(record) + "】该记录已经持久化！");
        }
        return getRepository().save(mergeCreateOrUpdateObject(record, creator));
    }

    public List<T> create(List<T> records, String creator) throws DaoException {
        for (T record : records) {
            if (record.getId() != null && getRepository().exists(record.getId())) {
                throw new DaoException("创建失败，【" + JSON.toJSONString(record) + "】该记录已经持久化！");
            }
            record = mergeCreateOrUpdateObject(record, creator);
        }
        return getRepository().save(records);
    }

    /**
     * 更新，如果数据库中没有记录，则抛异常
     */
    public T update(T record, String updater) throws DaoException {
        if (record.getId() == null || !getRepository().exists(record.getId())) {
            throw new DaoException("更新失败，【" + JSON.toJSONString(record) + "】该记录尚未持久化！");
        }
        return getRepository().save(mergeCreateOrUpdateObject(record, updater));
    }

    public List<T> update(List<T> records, String updater) throws DaoException {
        for (T record : records) {
            if (record.getId() == null || !getRepository().exists(record.getId())) {
                throw new DaoException("更新失败，【" + JSON.toJSONString(record) + "】该记录尚未持久化！");
            }
            record = mergeCreateOrUpdateObject(record, updater);
        }
        return getRepository().save(records);
    }

    /**
     * 查找所有实体列表
     *
     * @return 返回实体列表
     */
    public List<T> selectAll() {
        return getRepository().findAll();
    }

    public List<T> selectByIds(List<String> ids) {
        return getRepository().findAll(ids);
    }

    /**
     * 查找所有记录数
     *
     * @return 返回实体记录数
     */
    public long countAll() {
        return getRepository().count();
    }

    /**
     * 查询是否存在记录
     */
    public boolean exists(String id) {
        return getRepository().exists(id);
    }

    /**
     * 搜索分页
     * StringMatcher 选项如下
     * CONTAINING ->   LOWER(column) like '%' + LOWER(?) + '%'
     * DEFAULT -> column = ?
     * INSENSITIVE -> LOWER(column) = LOWER(?)
     * 可自定义StringMatcher
     */
    public BasePage<T> selectStringContainingPageByExample(T t, Pageable pageable) {
        return selectPageByExampleAndExampleMatcher(t,pageable,
                ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING));
    }
    public List<T> selectStringContainingListByExample(T t) {
        return selectListByExampleAndExampleMatcher(t,
                ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING));
    }

    public long countStringContainingListByExample(T t){
        return countByExampleAndExampleMatcher(t,
                ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING));
    }


    public BasePage<T> selectStringDefaultPageByExample(T t, Pageable pageable){

        return selectPageByExampleAndExampleMatcher(t,pageable,
                ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.DEFAULT));
    }
    public List<T> selectStringDefaultListByExample(T t){
        return selectListByExampleAndExampleMatcher(t,
                ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.DEFAULT));
    }

    public long countStringDefaultListByExample(T t){
        return countByExampleAndExampleMatcher(t,
                ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.DEFAULT));
    }


    public BasePage<T> selectPageByExampleAndExampleMatcher(T t, Pageable pageable, ExampleMatcher exampleMatcher) {
        Example<T> example = Example.of(t, exampleMatcher);
        List<T> content = getRepository().findAll(example, pageable).getContent();
        return new BasePage<>(content,pageable.getPageNumber(),pageable.getPageSize(),countByExampleAndExampleMatcher(t,exampleMatcher));
    }
    public List<T> selectListByExampleAndExampleMatcher(T t, ExampleMatcher exampleMatcher) {
        Example<T> example = Example.of(t, exampleMatcher);
        return getRepository().findAll(example);
    }

    public long countByExampleAndExampleMatcher(T t,ExampleMatcher exampleMatcher) {
        Example<T> example = Example.of(t, exampleMatcher);
        return getRepository().count(example);
    }

    public BasePage<T> selectPageBySpecification(Specification<T> specification, Pageable pageable){
        List<T> content = getRepository().findAll(specification, pageable).getContent();
        return new BasePage<>(content,pageable.getPageNumber(),pageable.getPageSize(),countBySpecification(specification));
    }
    public List<T> selectListBySpecification(Specification<T> specification){
        return getRepository().findAll(specification);
    }
    public long countBySpecification(Specification<T> specification){
        return getRepository().count(specification);
    }


}
